<?php
/**
* @file Searchm.php
* @synopsis  搜索模块
* @author Yee, <rlk002@gmail.com>
* @version 1.0
* @date 2015-03-13 11:42:19
*/

defined('BASEPATH') OR exit('No direct script access allowed');

require_once('/usr/local/xunsearch/sdk/php/lib/XS.php');

class Searchm extends CI_Model
{
	public $xs;
	public $item;
	public $db;
	public $doc;
	function __construct($item_name = '')
	{
		$this->item = $item_name ? $item_name : '/usr/local/xunsearch/sdk/php/app/qingying.ini';
		$this->xs = new XS($this->item);
		$this->db = $this->load->database('default',true);
		$this->load->model('userm');
		$this->load->model('postm');
	}

	public function getuserrss($keyword,$user_id = 1,$page = 1,$perpage = 20)
	{
	try{
		$xs = new XS('/usr/local/xunsearch/sdk/php/app/rss.ini');
		$search = $xs->search;
		$search->setFuzzy(True);
		$search->setCharset('UTF-8');
		$search->setQuery("author_id:{$user_id} " . $keyword);
		$limitnum = ($page - 1) * $perpage;
    if($page > 0)
    {
    	$search->setLimit($perpage,$limitnum);
    }else
    {
     	$search->setLimit($perpage);
    }
    $search->setSort('datetime_int',false);
    	$docs = $search->search();
	}
	catch (XSException $e)
	{
		echo $e;
		return array();
	}
    $posts = [];
		foreach($docs AS $doc)
		{	
			$post_id = $doc->id;
			$posts[$doc->id] = $doc->id;
		}
		return $posts;
	}


	public function search($keyword,$page = 1,$perpage = 20,$observer_id = 0)
	{
		$search = $this->xs->search;
		$search->setCharset('UTF-8');
		if(!$keyword)
		{
			$docs = $search->getHotQuery();
		}else
		{
			$search->setFuzzy(true);
			$search->setAutoSynonyms(true);
			$search->setQuery($keyword);
			$limitnum = ($page - 1) * $perpage;
    	if($page > 0)
    	{
    		$search->setLimit($perpage,$limitnum);
    	}else
    	{
      	$search->setLimit($perpage);
    	}
    	//$search->setSort('datatype',True);
		$search->setSort('datetime_int',False,True);
			$docs = $search->search();
		}

		$data = array();
		$users = array();
		$posts = array();
		$ppp = array();
		foreach($docs AS $val)
		{
			$ndata = array();
			if($val->datatype == 1)
			{
				/*
				$user = $this->userm->get_one_user_4_search($val->realid,$observer_id);
				if($user)
				{
					$users[] = $user;
				}
				*/	
			}else
			{
				$post = $this->postm->get_one_post_4_search($val->realid,$observer_id);
				//有内容并且未被屏蔽
				$this->load->model('hatem');
				if($post && !$this->hatem->get_hate_count($this->uid,$post["author_id"]))
				{
					$posts[] = $post;
				}
			}
		}
		
		$users = array();
		$suser = $this->userm->searchUser($keyword,$page,$perpage);
		foreach($suser AS $v)
		{
			$user = $this->userm->get_one_user_4_search($v['id'],$observer_id);
			if($user)
			{
				$users[] = $user;
			}
		}
		
		$data['userLists'] = $users;
		$data['userCount'] = count($users);
		$data['postLists'] = $posts;
		$data['postCount'] = count($posts);
		return $data;
	}

	/**
	 * 搜索病历 shiwuhao
	 * @param $keyword
	 * @param int $page
	 * @param int $perpage
	 * @param int $observer_id
	 * @return array
	 */
	public function search_post($keyword,$page = 1,$perpage = 20,$observer_id = 0)
	{
		$search = $this->xs->search;
		$search->setCharset('UTF-8');
		if(!$keyword)
		{
			$docs = $search->getHotQuery();
		}else
		{
			$search->setFuzzy(true);
			$search->setAutoSynonyms(true);
			$search->setQuery($keyword);
			$limitnum = ($page - 1) * $perpage;
			if($page > 0)
			{
				$search->setLimit($perpage,$limitnum);
			}else
			{
				$search->setLimit($perpage);
			}
			//$search->setSort('datatype',True);
			$search->setSort('datetime_int',False,True);
			$docs = $search->search();
		}

		$data = array();
		$users = array();
		$posts = array();
		$post_ids = array();
		foreach($docs AS $val)
		{
			$ndata = array();
			if($val->datatype == 1)
			{
				/*
				$user = $this->userm->get_one_user_4_search($val->realid,$observer_id);
				if($user)
				{
					$users[] = $user;
				}
				*/
			}else
			{
                if(in_array($val->realid, $post_ids))
                {
                    continue;
                }
                $post_ids[] = $val->realid;
				$post = $this->postm->get_one_post_4_search($val->realid,$observer_id);
				//有内容并且未被屏蔽
//				if($post && !$this->tmm->get_hate_count(array("hate_id"=>$post["author_id"])))
                if($post)
				{
					$posts[] = $post;
				}
			}
		}

		$data['postLists'] = $posts;
		$data['postCount'] = count($posts);
		return $data;
	}

	/**
	 * 通过coreseek 搜索帖子内容
	 * @param $keyword
	 * @param int $page
	 * @param int $perpage
	 * @param int $observer_id
	 */
	public function search_post_by_coreseek($keyword,$page = 1,$per_page = 20)
	{
		$start = ($page - 1) * $per_page;
		$this->load->model('sphinxm');
		$sphinx = $this->sphinxm->getInstance(CORESEEK_IP_POST, CORESEEK_PORT_POST);
		$sphinx->SetRankingMode(SPH_RANK_PROXIMITY_BM25 );
		$sphinx->SetLimits($start, $per_page);
		$sphinx->SetSortMode(SPH_SORT_EXTENDED, "@id desc");
		$res = $sphinx->Query($keyword, 'post');

		if (!$res['matches']) return array();

		$list = array();
		foreach($res['matches'] as $item) {
			$post_info = $this->postm->get_one_post_info($item['id'], 1, 1);
			if ($post_info) $list[] = $post_info;
		}

		$response = array('postLists' => $list, 'postCount' => $res['total']);
		return $response;
	}

	public function hotword($num = '10')
	{
		$search = $this->xs->search;
		$new = array();
		$hotword_array = $search->getHotQuery($num);
		$hotword = array();
		foreach ($hotword_array as $key=>$val) {
			$hotword[] = $key;
		}
		$fl = $this->db->select('thread_name')->from('ml_thread')->where("parent_id>","2")->get()->result_array();
		$fla = array();
		foreach($fl AS $val)
		{
			if(!in_array($val['thread_name'],$hotword))
			{
				$fla[] = $val['thread_name'];
			}
			else
			{
				continue;
			}
		}

		$new = array_merge($hotword,$fla);
		$return = array();
		foreach ($new as $value) {
			$return[] = (string)$value;
		}
		return $return;
	}
	
	
	public function buildindex($isrebuild = 0)
	{
		$index = $this->xs->index;
		if(!$isrebuild)
		{
			$lasetime = $this->db->select()->from('ml_indexbuild')->order_by('timestamp','DESC')->limit(1)->get()->result_array();
			if($lasetime && $lasetime[0])
			{
				$lasetime = $lasetime[0]['timestamp'];
			}else
			{
				$lasetime = 0;
			}
		}else
		{
			$lasetime = 0;
			$index->clean();
		}
		$ret = $this->db->select("id,username,add_time,head_ico")->from('ml_fellow')->where('add_time>=',$lasetime)->order_by('id','asc')->get()->result_array();
		$index->openBuffer();
		foreach($ret AS $val)
		{
			$row = array();
			$row['id'] = $val['id'];
			$row['realid'] = $val['id'];
			$row['content'] = $val['username'];
			$row['content_full'] = $val['username'];
			$row['cate'] = '-99';
			$row['datatype'] = 1;
			$row['datetime'] = date('Ymd',$val['add_time']);
			$row['datetime_int'] = $val['add_time'];
			$row['postimg'] = $val['head_ico'] ? $val['head_ico'] : '';
			$index->openBuffer();
			$doc = new XSDocument;
			$doc->setFields($row);
			$index->add($doc);
		}
		$index->closeBuffer();
		$index->openBuffer();
		$ret = $this->db->select('id,message,typeid,addtime,post_imgs')->from('ml_post')->where('is_show',1)->where('addtime>',$lasetime)->order_by('id','asc')->get()->result_array();
        //$sql = "select id,message,typeid,addtime,post_imgs from ml_post where (id < ".(string)($i + 4000)." and id > ".(string)($i).") and is_show=1 and addtime>".$lasetime." order by id asc";
		foreach($ret AS $val)
		{
			$row = array();
			$row['id'] = $val['id'] + 1000000000;
			$row['realid'] = $val['id'];
			$cate = $this->get_post_cate($val['id']);
			$row['content'] = $cate ? $val['message'] . "#{$cate}" : $val['message'];
			$row['cate'] = $val['typeid'] ? $val['typeid'] : '0';
			$row['content_full'] = $val['message'];
			$row['datatype'] = 2;
			$row['datetime'] = date('Ymd',$val['addtime']);
			$row['datetime_int'] = $val['addtime'];
			$images = $val['post_imgs'];
			if($images)
			{
				$imagesexplode = explode(',',$images);
				$row['postimg'] = $imagesexplode[0];
			}else
			{
				$row['postimg'] = '';
			}
			$comments = '';
			$commentquery = $this->db->select('message')->from('ml_comment')->where('post_id',$val['id'])->where('is_show',1)->order_by('id','asc')->get()->result_array();
			foreach($commentquery AS $cv)
			{
				$comments .= " {$cv['message']} ";
			}
			$comments && $row['content'] .= $comments;
			$doc = new XSDocument;
			$doc->setFields($row);
			$index->add($doc);
		}
		$index->closeBuffer();
		if(!$isrebuild)
		{
			$this->db->set('timestamp',time())->insert('ml_indexbuild');
		}
	}

	public function buildrssindex()
	{
		$xs = new XS("/usr/local/xunsearch/sdk/php/app/rss.ini");
		$index = $xs->index;
		$index->clean();
		$lasetime = 0;
		$ret = $this->db->select()->from('ml_post')->where('addtime>',$lasetime)->order_by('id','asc')->get()->result_array();
		foreach($ret AS $val)
		{
			$row = array();
			$row['id'] = $val['id'];
			$cate = $this->get_post_cate($val['id']);
			$row['content'] = $val['typeid'] ? $val['typeid'] : '';
			if(!$row['content'])
			{
				continue;
			}
			$row['author_id'] = (int)$val['author_id'];
			$row['datetime'] = date('Ymd',$val['addtime']);
			$row['datetime_int'] = $val['addtime'];
			$index->openBuffer();
			$doc = new XSDocument;
			$doc->setFields($row);
			$index->add($doc);
			$index->closeBuffer();
		}
	}

	public function get_post_cate($post_id)
	{
		$this->load->model('type_weightm');
		$this->load->model('postm');
		$post = $this->type_weightm->get_post_type_weight($post_id);
		$str = "";
		foreach($post AS $val)
		{
			$type_name = $this->postm->get_type_name($val['type_id']);
			if($type_name && $type_name[0])
			{
				$str .= $type_name[0]['thread_name'] . "!";
			}
		}
		if($str)
		{
			return $str;
		}else
		{
			return '';
		}
	}

	protected function getResultArray($res)
	{
		$total_found = isset($res["total_found"]) ? $res["total_found"] : 0;

		$data = $res["matches"];
		if (!empty($data)) {
			$data = array_column($data, "attrs");
		}
		else {
			$data = array();
		}

		return array("list" => $data, "count"=> $total_found);
	}
	
	public function searchUserFirstPage($keyword, $num_special = 6)
	{
		if (is_array($keyword)) {
			$keyword = implode(" ", $keyword);
		}

		$this->load->model('sphinxm');
		$sphinx = $this->sphinxm->getInstance(CORESEEK_IP_USER, CORESEEK_PORT_USER);
		$sphinx->SetRankingMode(SPH_RANK_PROXIMITY_BM25 );
		$sphinx->SetSortMode(SPH_SORT_EXTENDED, 'user_level DESC, verified_status DESC, @weight DESC');

		$sphinx->SetLimits(0, $num_special);
		$sphinx->SetFilter("user_level", [5]);
		$sphinx->AddQuery($keyword, 'fellow');

		$sphinx->ResetFilters();
		$sphinx->SetLimits(0, 10);
		$sphinx->SetFilter("user_level", [0]);
		$sphinx->AddQuery($keyword, 'fellow');

		$res = $sphinx->RunQueries();

		$arr_special = $this->getResultArray($res[0]);
		$arr_normal = $this->getResultArray($res[1]);

		return array($arr_special, $arr_normal);
	}

	public function searchUser($keyword, $where, $page = 1, $per_page = 20)
	{
		if (is_array($keyword)) {
			$keyword = implode(" ", $keyword);
		}

		$start = intval(($page - 1) * $per_page);
		$per_page = intval($per_page);

		$this->load->model('sphinxm');
		$sphinx = $this->sphinxm->getInstance(CORESEEK_IP_USER, CORESEEK_PORT_USER);
		$sphinx->SetRankingMode(SPH_RANK_PROXIMITY_BM25 );
		$sphinx->SetLimits($start, $per_page);
		$sphinx->SetSortMode(SPH_SORT_EXTENDED, 'user_level DESC, verified_status DESC, @weight DESC');


		if ($where) {
			unset($where["thread"]);
			foreach ($where as $k => $v) {
				$sphinx->SetFilter($k, [$v]);
			}
		}
		$res = $sphinx->Query($keyword, 'fellow');

		$result = $this->getResultArray($res);

		return $result;
	}

	/**
	 * @param $name_arr
	 * @param $factor: 推荐系数, 默认应大于0.5, 如: 输入为10家医院,$factor为0.7, 则至少名称相同的医院要有7个才可以
	 * @return string
	 */
	protected function calSuggestName($name_arr, $factor)
	{
		$num_input = count($name_arr);

		# 只有一个, 无需推荐
		if ($num_input == 1) {
			return '';
		}

		$max_num = 0;		// 出现次数最多的名字对应次数
		$suggest = '';		// 出现次数最多的名字

		$tmp = array();
		foreach ($name_arr as $i => $name) {
			if (!isset($tmp[$name])) {
				$tmp[$name] = 1;
			}
			else {
				$tmp[$name] += 1;
			}

			if ($tmp[$name] > $max_num) {
				$suggest = $name;
				$max_num = $tmp[$name];
			}

			# 未达到推荐阈值, 例如: i=9,$factor = 0.7, 那么 $max_num 至少是 7
			if ($i + 1 - $max_num > $num_input * (1 - $factor)) {
				$suggest = '';
				break;
			}
		}

		return $suggest;
	}

	public function getSuggestHospitalName($arr_special, $arr_normal, $keyword)
	{
		$hname_arr = array_column($arr_special["list"], "practice_hospital");
		$hname_suggest = $this->calSuggestName($hname_arr, 0.7);

		if (!$hname_suggest) {
			$hname_arr = array_column($arr_normal["list"], "practice_hospital");
			$hname_suggest = $this->calSuggestName($hname_arr, 0.55);
		}

		return $hname_suggest;
	}

	public function retThreadListByHospital($keyword)
	{
		$this->load->model('sphinxm');
		$sphinx = $this->sphinxm->getInstance(CORESEEK_IP_USER, CORESEEK_PORT_USER);
		$sphinx->SetRankingMode(SPH_RANK_PROXIMITY_BM25 );
		$sphinx->SetLimits(0, 100);

		$sphinx->SetGroupBy('thread', SPH_GROUPBY_ATTR, 'thread asc');

		$res = $sphinx->Query($keyword, 'fellow');
		
		$group_by_results = $this->getResultArray($res);

		if (!$group_by_results["count"]) {
			return array();
		}

		$this->load->model('threadm');
		$sphinx->ResetGroupBy();

		$sphinx->SetLimits(0, 3);

		$num_thread = count($group_by_results["list"]);
		$size = 32;		// coreseek 限制 multisearch
		$round = intval(($num_thread - 1) / $size) + 1;
		$res = array();
		for ($i = 0; $i < $round; $i++) {
			$part = array_slice($group_by_results["list"], $i * $size, $size);

			foreach ($part as $item) {
				$thread_id = $item["thread"];

				$sphinx->ResetFilters();
				$sphinx->SetFilter("thread", [$thread_id]);
				$sphinx->SetFilter("user_level", [0]);
				$sphinx->AddQuery($keyword, 'fellow');
			}
			$tmp = $sphinx->RunQueries();
			$res = array_merge($res, $tmp);
		}

		$result = array();
		foreach ($res as $itm) {
			$thread_short_arr = $this->getResultArray($itm);
			if (!$thread_short_arr["count"]) {
				continue;
			}

			$result[] = $thread_short_arr;
		}
		
		return $result;
	}


	public function extractUidsByResult($result)
	{
		$uids = array();
		if (isset($result["list"]) && $result["list"]) {
			$uids = array_column($result["list"], "uid");
		}
		return $uids;
	}

	public function getResultBlockUserList($search_result_arr, $userinfo_arr)
	{
		if (!isset($search_result_arr["count"]) || !isset($search_result_arr["list"])) {
			return [];
		}
		if (!$search_result_arr["count"] || !$search_result_arr["list"]) {
			return [];
		}
		
		$result = array();

		foreach ($search_result_arr["list"] as $search_result) {
			$uid = $search_result["uid"];

			$user_info = isset($userinfo_arr[$uid]) ? $userinfo_arr[$uid] : null;
			if (!$user_info) {
				continue;
			}

			if ($this->pid == 2002) {
				$user_info['post_title'] = '';
			}
			$result[] = $user_info;
		}
		return $result;
	}

	public function getResultBlock($search_result_arr, $userinfo_arr, $thread_id = null)
	{
		if (!isset($search_result_arr["count"]) || !isset($search_result_arr["list"])) {
			return null;
		}
		if (!$search_result_arr["count"] || !$search_result_arr["list"]) {
			return null;
		}


		if (!isset($this->threadm)) {
			$this->load->model('threadm');
		}
		$result = array();
		if (isset($thread_id)) {
			if (!$thread_id) {
				$thread_name = "推荐专家";
				$thread_id = "0";
			}
			else {
				$thread_name = $this->threadm->get_thread_name($thread_id);
				$thread_id = strval($thread_id);
			}

			$result["thread_info"] = array('thread_id' => $thread_id, 'thread_name'=>$thread_name);
		}

		$result["user_list"] = $this->getResultBlockUserList($search_result_arr, $userinfo_arr);

		if (isset($thread_id) && $thread_id == 0) {
			# 兼容 Android 客户端一个bug: 取分组最后一个用户的thread作为该分组的thread
			if ($result["user_list"]) {
				$result["user_list"][count($result["user_list"]) - 1]["thread"] = '0';
			}
		}

		# 通过 user_count 控制是否加载更多
		$user_count = $search_result_arr["count"];
		if ($user_count <= 3) {
			$user_count = 0;		// 不显示加载更多
		}
		elseif ($thread_id == 0) {
			// 专家
		}
		$result["user_count"] = $user_count;

		return $result;
	}
}
